package com.jc.platform.anweiguo.service.base.impl;

import com.jc.platform.anweiguo.mapper.IPartnerMapper;
import com.jc.platform.anweiguo.mapper.IPurchaseContractMapper;
import com.jc.platform.anweiguo.mapper.IRPartnerPurchaseContractMapper;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;




import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jc.platform.common.annotation.DataIsolation;
import com.jc.platform.common.constants.GlobalConstant;
import com.jc.platform.common.constants.StringPool;
import com.jc.platform.common.model.UserInfo;
import com.jc.platform.common.model.QueryParam;
import com.jc.platform.common.result.PageInfo;
import com.jc.platform.common.result.ResultCodeEnum;
import com.jc.platform.common.result.ResultModel;
import com.jc.platform.common.search.SqlUtils;
import com.jc.platform.common.utils.BeanUtil;
import com.jc.platform.common.utils.RequestUtil;
import com.jc.platform.anweiguo.vo.PurchaseContractVO;
import com.jc.platform.anweiguo.entity.PurchaseContractEntity;
import com.jc.platform.anweiguo.mapper.IPurchaseContractMapper;
import com.jc.platform.anweiguo.service.base.impl.BaseServiceImpl;
import com.jc.platform.anweiguo.service.base.IBasePurchaseContractService;
import com.jc.platform.mybatis.utils.CollectCovertUtil;
import com.jc.platform.mybatis.utils.ConditionUtil;
import org.springframework.beans.factory.annotation.Autowired;

import org.activiti.bpmn.model.FormProperty;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.activiti.api.runtime.model.impl.ProcessInstanceImpl;
import java.util.concurrent.atomic.AtomicReference;
import org.springframework.beans.factory.annotation.Autowired;
import com.jc.platform.common.result.ResultCodeEnum;
import com.jc.platform.anweiguo.enums.WorkState;
import com.jc.platform.anweiguo.annotation.IsWorkflowEditField;
import org.activiti.api.task.model.payloads.CompleteTaskPayload;
import com.jc.platform.workflowengine.feign.IProcessServiceFeign;
import org.springframework.data.domain.PageRequest;
import com.jc.platform.workflow.common.model.ProcessVariable;
import com.jc.platform.workflow.common.model.impl.PlatformHisTaskImpl;
import com.jc.platform.workflow.common.model.impl.PlatformProcessInstanceHistoryImpl;
import com.jc.platform.workflow.common.model.impl.PlatformProcessInstanceImpl;
import com.jc.platform.workflow.common.model.impl.PlatformTaskImpl;
import com.jc.platform.workflow.common.enums.VariableGlobalEnum;
import com.jc.platform.workflow.common.enums.VariableLocalEnum;

import lombok.SneakyThrows;
import com.jc.platform.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.jc.platform.common.utils.CollectionUtil;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import com.jc.platform.anweiguo.mapper.IRPartnerPurchaseContractMapper;
import com.jc.platform.anweiguo.entity.RPartnerPurchaseContractEntity;

/**
 * ClassName AbstractPurchaseContractServiceImpl.java
 * Description 采购合同
 *
 * @author anweiguo
 * @version 3.0
 * @date 2021/08/07
 */
@Slf4j
public abstract class AbstractPurchaseContractServiceImpl extends BaseServiceImpl<PurchaseContractVO> implements IBasePurchaseContractService
{
	private static final String KEY_PREFIX = "db_platformAnweiguo:t_purchaseContract";

    @Autowired
    private RedisUtils<String, PurchaseContractVO> redisUtils;
    /**
     * 流程中心
     */
    @Autowired
    private IProcessServiceFeign processServiceFeign;
    @Autowired
    private IPartnerMapper partnerMapper;
    @Autowired
    private IPurchaseContractMapper purchaseContractMapper;
    @Autowired
    private IRPartnerPurchaseContractMapper rPartnerPurchaseContractMapper;



	@Override
	public ResultModel<PurchaseContractVO> insert(PurchaseContractVO purchaseContractVO)
	{
	    //工作流默认状态为草稿
        purchaseContractVO.setWorkflowState(WorkState.THE_DRAFT.VALUE);
		PurchaseContractEntity entity = new PurchaseContractEntity();
		entity.copyFormVO(purchaseContractVO);
		purchaseContractMapper.insert(entity);
        List <Long> purchaseContractList = purchaseContractVO.getPartnerList();
        if(CollectionUtil.isNotEmpty(purchaseContractList)){
            purchaseContractList.forEach(mtmId -> {
                RPartnerPurchaseContractEntity mtmEntity = new RPartnerPurchaseContractEntity();
                mtmEntity.setContractId(entity.getId());
                mtmEntity.setPartnerId(mtmId);
                rPartnerPurchaseContractMapper.insert(mtmEntity);
            });
        }

		purchaseContractVO.setId(entity.getId());
		delRedisKeyBatch(KEY_PREFIX);
		return ResultModel.success(purchaseContractVO);
	}

	@Override
	public ResultModel<PurchaseContractVO> update(PurchaseContractVO purchaseContract)
	{
		PurchaseContractEntity entity = new PurchaseContractEntity();
		entity.copyFormVO(purchaseContract);
		purchaseContractMapper.updateById(entity);

        rPartnerPurchaseContractMapper.deleteByContractId(purchaseContract.getId());
        List <Long> purchaseContractList = purchaseContract.getPartnerList();
        if(CollectionUtil.isNotEmpty(purchaseContractList)){
            purchaseContractList.forEach(mtmId -> {
                RPartnerPurchaseContractEntity mtmEntity = new RPartnerPurchaseContractEntity();
                mtmEntity.setContractId(purchaseContract.getId());
                mtmEntity.setPartnerId(mtmId);
                rPartnerPurchaseContractMapper.insert(mtmEntity);
            });
        }


		purchaseContract.setId(entity.getId());
		delRedisKeyBatch(KEY_PREFIX);
        delFromRedisAsync(entity.getId());
		entity = purchaseContractMapper.selectById(entity.getId());
		return ResultModel.success(entity.copyToVO());
	}

    @Override
	public ResultModel<Boolean> delete(Long id)
	{
        
         int count = purchaseContractMapper.deleteById(id);

        rPartnerPurchaseContractMapper.deleteByContractId(id);
		if (count > 0)
		{
			delRedisKeyBatch(KEY_PREFIX);
            delFromRedisAsync(id);
			return ResultModel.success(true);
		}
		else
		{
			return ResultModel.success(false);
		}
	}

    @Override
	public ResultModel<Boolean> deleteBatch(List<Long> ids)
	{
        ids.forEach(id -> {
            purchaseContractMapper.deleteById(id);
        });

        delRedisKeyBatch(KEY_PREFIX);
        return ResultModel.success(true);
	}




	@Override
	public Boolean checkNotExists(Long id, String property, String value)
	{
        QueryWrapper<PurchaseContractEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(BeanUtil.newInstance(PurchaseContractEntity.class));
        queryWrapper.eq(SqlUtils.getColumnByProperty(property), value);

        if(id!=null && id>0){
            queryWrapper.ne(StringPool.ID, id);
        }


        return purchaseContractMapper.selectCount(queryWrapper) <= 0;
	}

	@Override
	public ResultModel<PurchaseContractVO> get(Long id)
	{
        String redisKey = RedisUtils.getRedisKey(KEY_PREFIX, id);
        PurchaseContractVO purchaseContractVO = getRedis(redisKey);
        if (purchaseContractVO == null)
        {
            PurchaseContractEntity entity = purchaseContractMapper.selectById(id);
            if (entity == null){
                return ResultModel.failed();
            }
            purchaseContractVO = entity.copyToVO();

            purchaseContractVO.setPartnerPOList(CollectCovertUtil.listVO(partnerMapper.findByPurchaseContract(id)));

            setRedis(redisKey, purchaseContractVO);
        }
        return ResultModel.success(purchaseContractVO);
	}

	@Override
	@DataIsolation(value = { "group_id","org_id","dept_id","create_id"})
	public ResultModel<List<PurchaseContractVO>> find(QueryParam queryParam)
	{
		UserInfo userInfo = RequestUtil.getLoginUser();
		queryParam.getQuery().put("group_id",userInfo.getGroupId());
        String redisKey = RedisUtils.getRedisKey(KEY_PREFIX, "collection:find." + queryParam.toString());
        List<PurchaseContractVO> list = getRedisForList(redisKey);
            if (list == null || list.isEmpty())
            {
                QueryWrapper<PurchaseContractEntity> queryWrapper = ConditionUtil.getQueryWrapper(queryParam, PurchaseContractEntity.class);
                List<PurchaseContractEntity> entities = purchaseContractMapper.selectList(queryWrapper);
                list = CollectCovertUtil.listVO(entities);

                if (list != null && !list.isEmpty())
                {
                    if(CollectionUtil.isNotEmpty(list)){
                        list.stream().map(item -> {
                            item.setPartnerList(rPartnerPurchaseContractMapper.findPartnerIdByContractId(item.getId()));
                            return item;
                        })
                        .collect(Collectors.toList());
                    }
                    setRedis(redisKey,list);
                }
            }
        return ResultModel.success(list);
	}

	@Override
	@DataIsolation(value = { "group_id","org_id","dept_id","create_id"})
	public ResultModel<PageInfo<PurchaseContractVO>> finds(QueryParam queryParam)
	{
		UserInfo userInfo = RequestUtil.getLoginUser();
		queryParam.getQuery().put("group_id",userInfo.getGroupId());

        String redisKey = RedisUtils.getRedisKey(KEY_PREFIX, "collection:finds." + queryParam.toString());
        PageInfo<PurchaseContractVO> page = getRedisForPage(redisKey);
        if (page == null)
        {
            QueryWrapper<PurchaseContractEntity> queryWrapper = ConditionUtil.getQueryWrapper(queryParam, PurchaseContractEntity.class);
            IPage<PurchaseContractEntity> entityPage = purchaseContractMapper.selectPage(ConditionUtil.getPage(queryParam), queryWrapper);
            page = CollectCovertUtil.pageVO(entityPage);


            if(CollectionUtil.isNotEmpty(page.getList())){
                page.getList().stream().map(item -> {
                    item.setPartnerList(rPartnerPurchaseContractMapper.findPartnerIdByContractId(item.getId()));
                    return item;
                })
                .collect(Collectors.toList());
            }
            setRedis(redisKey,page);
        }
        return ResultModel.success(page);

	}

    @Override
	public ResultModel<Integer> count(QueryParam queryParam)
	{
        QueryWrapper<PurchaseContractEntity> queryWrapper = ConditionUtil.getQueryWrapper(queryParam, PurchaseContractEntity.class);
        Integer count = purchaseContractMapper.selectCount(queryWrapper);
		return ResultModel.success(count);
	}



    @SneakyThrows
	@Override
	public ResultModel<PurchaseContractVO> submit(PurchaseContractVO purchaseContractVO) {
		List showFiledList = new ArrayList();
		Field[] fieldList = purchaseContractVO.getClass().getDeclaredFields();
		for(int i = 0; i<fieldList.length; i++){
			String fieldName = fieldList[i].getName();
			IsWorkflowEditField annotation = fieldList[i].getAnnotation(IsWorkflowEditField.class);
			if(annotation == null){
				continue;
			}
			String enValue = annotation.value();
			showFiledList.add(new ProcessVariable(fieldName, enValue,
					null, false, null));
		}

		Map map = new HashMap();
		map.put(VariableLocalEnum.getVariableName(VariableLocalEnum.id), purchaseContractVO.getId());
		map.put(VariableGlobalEnum.getVariableName(VariableGlobalEnum.form), purchaseContractVO);
		map.put(VariableGlobalEnum.getVariableName(VariableGlobalEnum.showForm),showFiledList);
		map.put(VariableGlobalEnum.getVariableName(VariableGlobalEnum.invoke),purchaseContractVO.getRemoteCallPayload());

		// 是否工作流条件字段(需要在模板循环是否为条件字段，遍历写死)
        map.put("money",purchaseContractVO.getMoney());

		ResultModel<ProcessInstanceImpl> resultModel = processServiceFeign.startProcessInstanceByBusinessId(
				PurchaseContractVO.IS_ENTITY_CODE,
				Long.toString(purchaseContractVO.getId()),
				map);

		String code = resultModel.getCode();
		// 调起成功
		if (ResultCodeEnum.SUCCESS.code().equals(code)) {
			if (resultModel.getData() != null) {
				return ResultModel.success(purchaseContractVO);
			}
		// 未找到流程实例
		} else if (ResultCodeEnum.NOT_FOUND_PROCESS.code().equals(code)) {
			return ResultModel.failed(ResultCodeEnum.NOT_FOUND_PROCESS);
		}
		return ResultModel.failed();
	}
	@Override
	public ResultModel<List<PurchaseContractVO>> importData(List<PurchaseContractVO> purchaseContractList) {
		List<PurchaseContractEntity> saves = new ArrayList<>();
		List<PurchaseContractVO> returnList = new ArrayList<>();
		for (PurchaseContractVO purchaseContract : purchaseContractList) {
			PurchaseContractEntity entity = new PurchaseContractEntity();
			entity.copyFormVO(purchaseContract);
			saves.add(entity);
		}
		saves.forEach(entity -> {
			purchaseContractMapper.insert(entity);
			PurchaseContractVO purchaseContract = entity.copyToVO();
			returnList.add(purchaseContract);
		});
		return ResultModel.success(purchaseContractList);
	}
    /**
     * 执行【合作单位】添加
     *
     * @param id
     * @param partnerId
     * @return
     */
    private int doAddPartner(Long id, Long... partnerId) {
        int count = 0;
        for (Long _id : partnerId) {
            if(partnerMapper.selectById(_id) != null){
                count += purchaseContractMapper.addPartner(id, _id);
            }
        }
        return count;
    }

    /**
     * 设置【合作单位】
     *
     * @param id
     * @param partnerId
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public int setPartner(Long id, Long[] partnerId) {
        purchaseContractMapper.removeAllPartner(id);
        delFromRedisAsync(id);
        if(ArrayUtils.isEmpty(partnerId)){
            return 0;
        }
        return doAddPartner(id, partnerId);
    }





    private void delFromRedisAsync(Object id)
	{
		CompletableFuture.runAsync(() -> {
			try
			{
				TimeUnit.SECONDS.sleep(1);
				redisUtils.del(RedisUtils.getRedisKey(KEY_PREFIX, id));
			}
			catch (InterruptedException e)
			{
				log.error("缓存删除线程错误", e);
				Thread.currentThread()
					  .interrupt();
			}
		});
	}

	private void delColRedis()
	{
		String keyPattern = RedisUtils.getRedisKey(KEY_PREFIX, "collection:*");
		Set<String> keys = redisUtils.keys(keyPattern);
		if (keys != null)
		{
			String[] keyArray = keys.toArray(new String[] {});
			redisUtils.del(keyArray);
		}
	}
}

